package com.yonyou.pmclouds.workflow.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyou.pmclouds.basecom.billstatus.BillStatusConst;
import com.yonyou.pmclouds.basecom.entity.SuperVO;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.im.util.IMHttpTookit;
import com.yonyou.pmclouds.outter.user.UserInfoServerQuery;
import com.yonyou.pmclouds.task.rmiitf.TaskRemoteService;
import com.yonyou.pmclouds.user.entity.UserInfo;
import com.yonyou.pmclouds.workflow.entity.ApproveInfoParam;
import com.yonyou.pmclouds.workflow.entity.ProcessTaskVO;
import com.yonyou.pmclouds.workflow.service.ProcessTaskService;
import com.yonyou.pmclouds.workflow.service.rmiitf.IFlowApprove;
import com.yonyou.pmclouds.workflow.service.rmiitf.IWorkFlowService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import yonyou.bpm.rest.request.task.TaskQueryParam;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  异步调用审批操作
 *  @author zhangzhonghao
 */

@Component
@Slf4j
public class ApprovalFlowExecutor extends BatchExecutor{

    private final ProcessTaskService processTaskService;

    private final IFlowApprove flowApprove;

    private final TaskRemoteService taskRemoteService;

    private IWorkFlowService workFlowService;

    @Autowired(required = false)
    private ApproveCallBackMock approveCallBackMock;

    @Autowired
    public ApprovalFlowExecutor(ProcessTaskService processTaskService, IFlowApprove flowApprove, TaskRemoteService taskRemoteService, IWorkFlowService workFlowService) {
        this.processTaskService = processTaskService;
        this.flowApprove = flowApprove;
        this.taskRemoteService = taskRemoteService;
        this.workFlowService = workFlowService;
    }

    @Override
    public Object executeTaskImpl(Object value) {
        ApproveInfoParam approveInfoParam = (ApproveInfoParam) value;
        RuntimeEnvironment.setTenantId(approveInfoParam.getTenantId());
        RuntimeEnvironment.setLoginUserId(approveInfoParam.getUserId());
        try {
            //获取审批任务对象
            ProcessTaskVO[] processTaskVOs = getLatestBillTask(approveInfoParam.getPkBill(), RuntimeEnvironment.getLoginUserId());

            if (ArrayUtils.isEmpty(processTaskVOs))
                throw new BusinessException("用户没有该单据的审批任务，请刷新后重试");
            //完成任务
            completeProcessTask(approveInfoParam, processTaskVOs[0]);
            //再次获取新任务
            ProcessTaskVO[] newTaskVOs = getLatestBillTask(approveInfoParam.getPkBill(), null);

            if (ArrayUtils.isNotEmpty(newTaskVOs)) {
                taskRemoteService.insertTaskVOForWorkFlow(approveInfoParam, BillStatusConst.COMMON_APPROVING_STATUS, newTaskVOs);
            }else{
                // 不存在审批任务时即审批通过，将当前人的待办的单据状态置为审批通过，此操作是为了修改app端我发起功能中单据状态仍为审批中的问题
                taskRemoteService.updateBillStatus(approveInfoParam.getPkBill(), null, BillStatusConst.COMMON_APPROVED_STATUS);
                if(approveCallBackMock!=null){
                    approveCallBackMock.doMock(approveInfoParam.getPkBill(),approveInfoParam.getProcessDefinitionKey());
                }
            }
            return value;
        }catch (Exception e){
            log.error("审批通过失败：", e);
            // 将已办回滚为待办
            List<String> pkTasks = approveInfoParam.getPkTasks();
            if(pkTasks != null && pkTasks.size() > 0){
                try {
                    taskRemoteService.updateTaskStatus(pkTasks);
                } catch (BusinessException e1) {
                    log.error("审批失败后回滚待办信息失败：", e);
                }
            }
            try {
                workFlowService.updateBillStatus(approveInfoParam.getBillType(), approveInfoParam.getPkBill(), BillStatusConst.COMMON_APPROVING_STATUS);
            } catch (BusinessException ex) {
                log.error("审批失败后回滚单据信息失败：", e);
            }

            return null;
        }
    }

    private ProcessTaskVO[] getLatestBillTask(String pkBill, String pkUser) throws BusinessException {
        TaskQueryParam taskQueryParam = getTaskQueryParam(pkBill, pkUser);
        return processTaskService.queryProcessTaskVOs(taskQueryParam);
    }

    private TaskQueryParam getTaskQueryParam(String pkBill, String pkUser) {
        TaskQueryParam taskQueryParam = new TaskQueryParam();
        taskQueryParam.setProcessInstanceBusinessKey(pkBill);
        taskQueryParam.setAssignee(pkUser);
        return taskQueryParam;
    }

    private void completeProcessTask(ApproveInfoParam approveInfoParam, ProcessTaskVO processTaskVO) throws BusinessException {

        SuperVO businessVO = flowApprove.getBuziVOForWorkFlow(approveInfoParam.getPkBill(), approveInfoParam.getBillType());

        if (businessVO == null)
            throw new BusinessException("没有找到对应的业务单据");

        processTaskService.completeTask(processTaskVO.getTaskId(), approveInfoParam.getOpinion(), businessVO, approveInfoParam.getAssignInfo());
    }
}


/**
 * 用于模拟开发环境审批的回调
 * @author zhangwce
 */
@Component
@Slf4j
@Profile({"dev","temp"})
class ApproveCallBackMock{

    @Autowired
    private UserInfoServerQuery userInfoQuery;

    private ObjectMapper mapper = new ObjectMapper();
    @Value("${bpmrest.mockdata.customerhost:#{null}}")
    private String customerHost ;

    public void doMock(String pkBill , String processDefinitionKey) throws BusinessException{

//        private String businessKey;
//        private String userCode;
//        private String processDefinitionKey;
//        private String tenantCode;

        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("businessKey",pkBill);

        UserInfo userInfo = userInfoQuery.queryUser(RuntimeEnvironment.getLoginUserId());

        if(userInfo!= null)
            paramMap.put("userCode",userInfo.getUserCode());

        paramMap.put("processDefinitionKey",processDefinitionKey);
        paramMap.put("tenantCode","pmclouds_"+RuntimeEnvironment.getTenantId());

        String json = null;
        try {
            json = mapper.writeValueAsString(paramMap);
        } catch (Exception e) {
            throw new BusinessException(e.getMessage(),e.getCause());
        }

        String callBackUrl = "/outter/workflow/callback";

        if(StringUtils.isEmpty(customerHost))
            customerHost = "http://127.0.0.1:8080";

        String result = IMHttpTookit.doPostWithJson(customerHost+callBackUrl,json,null);

        log.error(result);

    }

}
